 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=153 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Swing threads
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='ColorTip,event,EventQueue,FetchQuotesAction,SwingUtilities,worker,thread,java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Swing threads</div>

<div class='main-body'>
 
<br><b>Event Dispatch Thread</b>
<p>In a Swing application, most of the processing takes place in a single,
special thread called the <i>event dispatch thread</i>.
<p>This thread becomes active after a component becomes <i>realized </i>:
either <tt>pack</tt>, <tt>show</tt>, or <tt>setVisible(true)</tt> has been
called. When a top level window is realized, all of its components are
also realized. Swing is mostly single-threaded : <span class='highlight'>almost all calls to
realized components should execute in the event dispatch thread</span>. The
thread-safe exceptions are
<ul>
<li>
some methods of <tt><a href="http://java.sun.com/javase/6/docs/api/javax/swing/JComponent.html">JComponent</a></tt>
: <tt>repaint</tt>, <tt>revalidate</tt>, <tt>invalidate</tt></li>

<li>
all <tt>addXXXListener</tt> and <tt>removeXXXListener</tt> methods</li>

<li>
all methods explicitly documented as thread-safe</li>
</ul>
<b>Worker Threads Keep GUIs Responsive</b>
<p>If a task needs a relatively long time to complete, then performing
that task in the event dispatch thread will cause the user interface to
become unresponsive for the duration of the task - the GUI becomes "locked".
Since this is undesirable, such tasks are usually performed outside the
event dispatch thread, on what is commonly referred to as a <i>worker thread</i>.
<p>When a worker thread completes its task, it needs a special mechanism
for updating realized GUI components, since, as stated above, realized
components almost always need to be updated only from the event dispatch
thread. Two methods of the <tt><a href="http://java.sun.com/javase/6/docs/api/java/awt/EventQueue.html">EventQueue</a></tt>
class, <tt>invokeLater</tt> and <tt>invokeAndWait</tt>, are provided for
this purpose (<tt><a href="http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html">SwingUtilities</a></tt>
has synonymous methods as well). Sun recommends using <tt>invokeLater</tt>
as the usual preferred style.
<p>When using threads, it is usually a good idea to use <em>daemon</em> threads,
not <em>user</em> threads, whenever possible : daemon threads will not prevent an
application from terminating. Since threads are user threads by default,
an explicit call to <tt>Thread.<a href="http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#setDaemon(boolean)">setDaemon</a>(true)</tt>
is required.

<P>The 
<tt><a href="http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html">SwingWorker</a></tt>
class was introduced in JSE 6, and should be used if available. 
The following examples use JSE 1.5.

<p><b>Example 1</b>
<p>The <a href="TopicAction028c-2.html">Splash Screen</a> topic (and in particular
its <tt>Launcher</tt> class) is a good example of using a worker thread.
Here, the status of the launch thread as a worker thread is exploited to
show a splash screen to the user, but only until the main window has finished
loading.
<p><b>Example 2</b>
<p>The <tt>ColorTip</tt> class, shown below, changes the background color
of a component for a short, fixed interval of time, as a simple way of
calling attention to that component.
<p>Its worker thread does not work very hard - it sleeps a lot. The calls
to <tt>sleep</tt> do not cause the GUI to become unresponsive, however,
since these calls do not take place in the event dispatch thread.
<p><tt>ColorTip</tt> has three <tt>private</tt>, <tt>Runnable</tt> nested
classes :
<ul>
<li>
<tt>Worker</tt> - inserts specific time intervals between changing colors</li>

<li>
<tt>ChangeColor</tt> - updates the GUI by changing the background color of
a target component</li>

<li>
<tt>RevertColor</tt> - updates the GUI by changing the background color back
to its original color</li>
</ul>
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.quotes;

<span class='keyword'>import</span> java.util.logging.*;
<span class='keyword'>import</span> java.awt.*;
<span class='keyword'>import</span> javax.swing.*;

<span class='keyword'>import</span> hirondelle.stocks.util.Consts;
<span class='keyword'>import</span> hirondelle.stocks.util.Args;
<span class='keyword'>import</span> hirondelle.stocks.util.Util;

<span class='comment'>/**
* Calls user's attention to an aspect of the GUI (much like a 
* &lt;tt&gt;ToolTip&lt;/tt&gt;) by changing the background color of a 
* component (typically a &lt;tt&gt;JLabel&lt;/tt&gt;) for a few seconds; 
* the component will always revert to its original background color 
* after a short time has passed.
*
* &lt;p&gt;Example use case:
&lt;pre&gt;
 //no initial delay, and show the new color for 2 seconds only
 ColorTip tip = new ColorTip(0, 2, someLabel, temporaryColor);
 tip.start();
&lt;/pre&gt;
* 
* Uses a daemon thread, so this class will not prevent a program from 
* terminating. Will not lock the GUI.
*/</span>
<span class='keyword'>final</span> <span class='keyword'>class</span> ColorTip {
  
  <span class='comment'>/**
  * Constructor. 
  *  
  * @param aInitialDelay number of seconds to wait before changing the 
  * background color of &lt;tt&gt;aComponent&lt;/tt&gt;, and must be in range 0..60 (inclusive).
  * @param aActivationInterval number of seconds to display &lt;tt&gt;aTempColor&lt;/tt&gt;, 
  * and must be in range 1..60 (inclusive).
  * @param aComponent GUI item whose background color will be changed.
  * @param aTempColor background color which &lt;tt&gt;aComponent&lt;/tt&gt; will take for 
  * &lt;tt&gt;aActivationInterval&lt;/tt&gt; seconds.
  */</span>
  ColorTip (
    <span class='keyword'>int</span> aInitialDelay, <span class='keyword'>int</span> aActivationInterval, JComponent aComponent, Color aTempColor
   ) {
    Args.checkForRange(aInitialDelay, <span class='literal'>0</span>, Consts.SECONDS_PER_MINUTE);
    Args.checkForRange(aActivationInterval, <span class='literal'>1</span>, Consts.SECONDS_PER_MINUTE);
    Args.checkForNull(aTempColor);
    fInitialDelay = aInitialDelay;
    fActivationInterval = aActivationInterval;
    fComponent = aComponent;
    fTemporaryColor = aTempColor;
    fOriginalColor = aComponent.getBackground();
    fOriginalOpacity = aComponent.isOpaque();
  }

  <span class='comment'>/**
  * Temporarily change the background color of the component, without interfering with 
  * the user's control of the gui, and without preventing program termination.
  *
  * &lt;P&gt;If the target temporary color is the same as the current background color, then 
  * do nothing. (This condition occurs when two &lt;tt&gt;ColorTip&lt;/tt&gt; objects are 
  * altering the same item at nearly the same time, such that they "overlap".)
  */</span>
  <span class='keyword'>void</span> start(){
    <span class='keyword'>if</span> ( isSameColor() ) <span class='keyword'>return</span>;
    Thread thread = <span class='keyword'>new</span> Thread( <span class='keyword'>new</span> Worker() );
    thread.setDaemon(<span class='keyword'>true</span>);
    thread.start();
  }
  
  <span class='comment'>// PRIVATE //
</span>  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>int</span> fInitialDelay;
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>int</span> fActivationInterval;
  <span class='keyword'>private</span> <span class='keyword'>final</span> JComponent fComponent;
  <span class='keyword'>private</span> <span class='keyword'>final</span> Color fTemporaryColor;
  <span class='keyword'>private</span> <span class='keyword'>final</span> Color fOriginalColor;
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>int</span> fCONVERSION_FACTOR = Consts.MILLISECONDS_PER_SECOND;
  
  <span class='comment'>/**
  * Stores the original value of the opaque property of fComponent.
  *  
  * Changes to the background color of a component 
  * take effect only if the component is in charge of drawing its background.
  * This is defined by the opaque property, which needs to be true for these
  * changes to take effect.
  *
  * &lt;P&gt;If fComponent is not opaque, then this property is temporarily
  * changed by this class in order to change the background color.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>boolean</span> fOriginalOpacity;
  
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(ColorTip.<span class='keyword'>class</span>);

  <span class='comment'>/**
  * Return true only if fTemporaryColor is the same as the fOriginalColor. 
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>boolean</span> isSameColor(){
    <span class='keyword'>return</span> fTemporaryColor.equals(fOriginalColor);
  }
  
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> Worker <span class='keyword'>implements</span> Runnable {
    <span class='keyword'>public</span> <span class='keyword'>void</span> run(){
      <span class='keyword'>try</span> {
        fLogger.fine(<span class='literal'>"Initial Sleeping..."</span>);
        Thread.sleep(fCONVERSION_FACTOR * fInitialDelay);
        EventQueue.invokeLater( <span class='keyword'>new</span> ChangeColor() );
        fLogger.fine(<span class='literal'>"Activation Sleeping..."</span>);
        Thread.sleep(fCONVERSION_FACTOR * fActivationInterval);
        EventQueue.invokeLater( <span class='keyword'>new</span> RevertColor() );
      }
      <span class='keyword'>catch</span> (InterruptedException ex) {
        fLogger.severe(<span class='literal'>"Cannot sleep."</span>);
      }
      fLogger.fine(<span class='literal'>"Color worker done."</span>);
    }
  }
  
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> ChangeColor <span class='keyword'>implements</span> Runnable {
    <span class='keyword'>public</span> <span class='keyword'>void</span> run(){
      <span class='keyword'>if</span> ( ! fOriginalOpacity ) {
        fComponent.setOpaque(<span class='keyword'>true</span>);
      }
      fComponent.setBackground(fTemporaryColor);
    }
  }
  
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> RevertColor <span class='keyword'>implements</span> Runnable {
    <span class='keyword'>public</span> <span class='keyword'>void</span> run(){
      fComponent.setBackground(fOriginalColor);
      fComponent.setOpaque(fOriginalOpacity);
    }
  }
}
 
</PRE>
<br>
<p><b>Example 3</b>
<p>The <tt>FetchQuotesAction</tt> class fetches current stock price data
from a source on the web. Since this may take a few seconds to process,
it uses a worker thread.
<p><tt>FetchQuotesAction</tt> uses two <tt>private</tt>, <tt>Runnable</tt>
nested classes, in what is probably a typical style :
<ul>
<li>
<tt>HardWorker</tt> - performs an intensive task (here, fetches stock price
data from the web)</li>

<li>
<tt>GuiUpdater</tt> - updates GUI components with the results of <tt>HardWorker</tt>
(here, displays current stock price data)</li>
</ul>
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.quotes;

<span class='keyword'>import</span> java.awt.event.*;
<span class='keyword'>import</span> java.awt.*;
<span class='keyword'>import</span> javax.swing.*;
<span class='keyword'>import</span> java.util.logging.*;
<span class='keyword'>import</span> java.util.*;
<span class='keyword'>import</span> java.text.MessageFormat;

<span class='keyword'>import</span> hirondelle.stocks.util.Consts;
<span class='keyword'>import</span> hirondelle.stocks.util.Util;
<span class='keyword'>import</span> hirondelle.stocks.util.Args;
<span class='keyword'>import</span> hirondelle.stocks.util.DataAccessException;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.UiConsts;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.UiUtil;

<span class='keyword'>import</span> hirondelle.stocks.portfolio.CurrentPortfolio;
<span class='keyword'>import</span> hirondelle.stocks.table.QuoteTable;
<span class='keyword'>import</span> hirondelle.stocks.preferences.QuoteTablePreferencesEditor;

<span class='comment'>/**
* Fetch current quote data for the {@link CurrentPortfolio} from a data 
* source on the web.
*
* &lt;P&gt;This action is performed at many different times :
*&lt;ul&gt;
* &lt;li&gt;once upon startup
* &lt;li&gt;periodically, at an interval configured by the user
* &lt;li&gt;when the end user explicitly requests a refresh of quote info
* &lt;li&gt;when the user makes a change to the current portfolio
*&lt;/ul&gt;
*
* &lt;P&gt;This class performs most of its work in a background daemon thread, and uses 
* &lt;tt&gt;EventQueue.invokeLater&lt;/tt&gt; to update the user interface with the result. 
* The user interface remains responsive, regardless of the time taken for its 
* work to complete.
*
* &lt;P&gt;A daemon thread is used since daemon threads do not prevent an application 
* from terminating.
*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> FetchQuotesAction <span class='keyword'>extends</span> AbstractAction <span class='keyword'>implements</span> Observer {

  <span class='comment'>/**
  * Constructor.
  *  
  * @param aCurrentPortfolio an &lt;tt&gt;Observable&lt;/tt&gt; which notifies this 
  * object when the {@link CurrentPortfolio} is changed
  * @param aQuoteTablePrefEditor allows this class to read the user preference
  * for the frequency of periodic fetches
  * @param aQuoteTable a GUI element which is updated when a fetch is performed
  * @param aSummaryView a GUI element which is updated when a fetch is performed
  */</span>
  <span class='keyword'>public</span> FetchQuotesAction (
    CurrentPortfolio aCurrentPortfolio, 
    QuoteTablePreferencesEditor aQuoteTablePrefEditor, 
    QuoteTable aQuoteTable, 
    SummaryView aSummaryView
  ) {
    <span class='keyword'>super</span>(<span class='literal'>"Update"</span>, UiUtil.getImageIcon(<span class='literal'>"/toolbarButtonGraphics/general/Refresh"</span>)); 
    Args.checkForNull(aQuoteTable);
    Args.checkForNull(aSummaryView);
    fCurrentPortfolio = aCurrentPortfolio;
    
    fQuoteTablePrefEditor = aQuoteTablePrefEditor;
    
    fQuoteTable = aQuoteTable;
    fSummaryView = aSummaryView;
    
    putValue(SHORT_DESCRIPTION, <span class='literal'>"Fetch updated stock quotes from web"</span>);
    putValue(
      ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, UiConsts.NO_KEYSTROKE_MASK)
    );      
    putValue(
      LONG_DESCRIPTION, 
      <span class='literal'>"Retrieves fresh stock quotes and displays it to the user in a table."</span>
    );
    putValue(MNEMONIC_KEY, <span class='keyword'>new</span> Integer(KeyEvent.VK_U) );    

    fUpdateFreq = fQuoteTablePrefEditor.getUpdateFrequency();
  }

  <span class='comment'>/**
  * Start an internal timer.
  * &lt;P&gt;This method must be called immediately after calling the constructor. 
  * Since this operation uses a 'this' reference, it cannot be included in the 
  * constructor itself.  
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>void</span> startTimer(){
    fQuoteTablePrefEditor.addObserver(<span class='keyword'>this</span>);
    fCurrentPortfolio.addObserver(<span class='keyword'>this</span>);
    fTimer = <span class='keyword'>new</span> javax.swing.Timer(fUpdateFreq * CONVERSION_FACTOR, <span class='keyword'>this</span>);
    fTimer.start();
  }

  <span class='comment'>/** Fetch quotes from the web for the &lt;tt&gt;CurrentPortfolio&lt;/tt&gt;.  */</span>
  <span class='keyword'>public</span> <span class='keyword'>void</span> actionPerformed(ActionEvent e) {
    fLogger.info(<span class='literal'>"Fetching quotes from web."</span>);
    fSummaryView.showStatusMessage(<span class='literal'>"Fetching quotes..."</span>);
    Thread worker = <span class='keyword'>new</span> Thread(<span class='keyword'>new</span> HardWorker());
    worker.setDaemon(<span class='keyword'>true</span>);
    worker.start();
  }
  
  <span class='comment'>/**
  * Listens for changes to the &lt;tt&gt;CurrentPortfolio&lt;/tt&gt; or the user
  * preference for update frequency, and calls {@link #actionPerformed}.
  *
  * &lt;P&gt;In the case of changes to the update frequency, &lt;tt&gt;actionPerformed&lt;/tt&gt; is 
  * called only if the udate frequency has been assigned a new value.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>void</span> update(Observable aPublisher, Object aData) {
    fLogger.fine(<span class='literal'>"Notified ..."</span>);
    <span class='keyword'>if</span> ( aPublisher == fQuoteTablePrefEditor ) {
      fLogger.fine(<span class='literal'>"By StocksTablePrefEditor..."</span>);
      <span class='keyword'>boolean</span> hasChangedFreq = fQuoteTablePrefEditor.getUpdateFrequency()!= fUpdateFreq;
      <span class='keyword'>if</span> ( hasChangedFreq ) restartTimer();
    }
    <span class='keyword'>else</span> {
      fLogger.fine(<span class='literal'>"By Current Portfolio..."</span>);
      actionPerformed(<span class='keyword'>null</span>);
    }
  } 

  <span class='comment'>// PRIVATE //
</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(FetchQuotesAction.<span class='keyword'>class</span>);
  
  <span class='comment'>/**
  * The set of {@link Stock} objects in which the user 
  * is currently interested.
  */</span>
  <span class='keyword'>private</span> CurrentPortfolio fCurrentPortfolio;
  
  <span class='comment'>/**
  * Edits user preferences attached to a table which presents quote data, and 
  * allows read-only programmatic access to such preferences.
  */</span>
  <span class='keyword'>private</span> QuoteTablePreferencesEditor fQuoteTablePrefEditor;
  
  <span class='comment'>/**
  * GUI element which is updated whenever a new set of quotes is obtained.
  */</span>
  <span class='keyword'>private</span> QuoteTable fQuoteTable;

  <span class='comment'>/**
  * GUI element which is updated whenever a new set of quotes is obtained.
  */</span>
  <span class='keyword'>private</span> SummaryView fSummaryView;
  
  <span class='comment'>/**
  * Periodically fetches quote data.
  *
  * &lt;P&gt;Use of a Swing Timer is acceptable here, in spite of the fact that the task
  * takes a long time to complete, since the task does &lt;em&gt;not&lt;/em&gt; in fact get 
  * executed on the event-dispatch thread (See below.)
  */</span>
  <span class='keyword'>private</span> javax.swing.Timer fTimer;
  
  <span class='comment'>/**
  * The number of minutes to wait between fetches of quote information.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>int</span> fUpdateFreq;
  
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> CONVERSION_FACTOR = 
    Consts.MILLISECONDS_PER_SECOND * Consts.SECONDS_PER_MINUTE
  ;

  <span class='comment'>/**
  * Perform the fetch, and update the GUI elements using the event dispatch 
  * thread.
  *
  * &lt;P&gt;Should be run as a daemon thread, such that it never prevents the application
  * from exiting.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> HardWorker <span class='keyword'>implements</span> Runnable {
    <span class='keyword'>public</span> <span class='keyword'>void</span> run() {
      <span class='comment'>//simulateLongDelay();
</span>      <span class='keyword'>try</span> {
        java.util.List&lt;Quote&gt; quotes = fCurrentPortfolio.getPortfolio().getQuotes();
        EventQueue.invokeLater( <span class='keyword'>new</span> GuiUpdater(quotes) );
      }
      <span class='keyword'>catch</span>(DataAccessException ex) {
        EventQueue.invokeLater( <span class='keyword'>new</span> GuiUpdater(ex) );
      }
    }
  }
  
  <span class='comment'>/**
  * Update the user interface after the fetch completes.
  *
  * &lt;P&gt;Must be run on the event dispatch thread. If the fetch fails for any reason, 
  * then any current quote data is left as is, and an error message is displayed in 
  * a status message.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> GuiUpdater <span class='keyword'>implements</span> Runnable {
    GuiUpdater( java.util.List&lt;Quote&gt; aQuotes ){
      fQuotes = aQuotes;
    }
    GuiUpdater(DataAccessException ex){
      <span class='comment'>//the exception is not used in this implementation
</span>    }
    <span class='keyword'>public</span> <span class='keyword'>void</span> run(){
      <span class='keyword'>if</span> (fQuotes != <span class='keyword'>null</span>){
        fQuoteTable.setQuoteTable( fQuotes );
        fSummaryView.setQuotes( fQuotes );
        StringBuilder warning = <span class='keyword'>new</span> StringBuilder();
        <span class='keyword'>if</span> ( hasNoZeroPrices(warning) ){
          fSummaryView.showStatusMessage(<span class='literal'>"Done."</span>);
        }
        <span class='keyword'>else</span> {
          fSummaryView.showStatusMessage(warning.toString());
        }
      }
      <span class='keyword'>else</span> {
        fSummaryView.showStatusMessage(<span class='literal'>"Failed - Please connect to the web."</span>);
      }
    }
    <span class='keyword'>private</span> java.util.List&lt;Quote&gt; fQuotes;
    <span class='keyword'>private</span> MessageFormat fTickerWarningFormat = 
      <span class='keyword'>new</span> MessageFormat(<span class='literal'>"Warning - no price for ticker {0} ({1})"</span>)
    ;
    <span class='keyword'>private</span> <span class='keyword'>boolean</span> hasNoZeroPrices(StringBuilder aMessage){
      <span class='keyword'>for</span>(Quote quote: fQuotes){
        <span class='keyword'>if</span> ( Util.isZeroMoney(quote.getPrice()) ) {
          Object[] params = {
            quote.getStock().getTicker(), 
            quote.getStock().getExchange()
          };
          aMessage.append(fTickerWarningFormat.format(params));
          <span class='keyword'>return</span> <span class='keyword'>false</span>;
        }
      }
      <span class='keyword'>return</span> <span class='keyword'>true</span>;
    }
  }
  
  <span class='comment'>/** Use for testing purposes only.  */</span>
  <span class='keyword'>private</span> <span class='keyword'>void</span> simulateLongDelay(){
    <span class='keyword'>try</span> {
      Thread.sleep(<span class='literal'>20000</span>);
    }
    <span class='keyword'>catch</span> (InterruptedException ex) {
      System.out.println(ex);
    }
  }
  
  <span class='keyword'>private</span> <span class='keyword'>void</span> restartTimer(){
    fLogger.fine(<span class='literal'>"Resetting initial delay and delay to: "</span> + fUpdateFreq + <span class='literal'>" minutes."</span>);
    fUpdateFreq = fQuoteTablePrefEditor.getUpdateFrequency();
    fTimer.setInitialDelay(fUpdateFreq * CONVERSION_FACTOR);
    fTimer.setDelay(fUpdateFreq * CONVERSION_FACTOR);
    fLogger.fine(<span class='literal'>"Cancelling pending tasks, and restarting timer..."</span>);
    fTimer.restart();
  }
}
 
</PRE>
<br>
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicAction028c-2.html?Id=149'>Splash screen</a> <br>
 
  
  <a href='TopicAction6407-2.html?Id=160'>Timers</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='153'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=153 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
